﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Engine.Sgml.Merging;
using System.Diagnostics;

namespace Engine.Sgml.Allocation {
    class BlockNodeNavigator {
        private InconsistentBlock block;
        private TreeNodeIterator treeNodeIterator;
        private InconsistentBlockAllocator blockAllocator;
        private SElement current;

        public BlockNodeNavigator(InconsistentBlock block) {

            }

        public SElement Current {
            get { return current; }
            }

        public void Reset(InconsistentBlock inconsistentBlock) {
            Guard.ArgumentNotNull(inconsistentBlock, "inconsistentBlock");
            Debug.Assert(inconsistentBlock != null);

            current = null;
            block = inconsistentBlock;
            TreeNodeItem first = new TreeNodeItem { Element = block.FirstElement.PreviousNonCommentNode(), Location = TreeNodeLocation.Previous };
            TreeNodeItem second = new TreeNodeItem { Element = block.LastElement.NextNonCommentNode(), Location = TreeNodeLocation.Next };
            treeNodeIterator.Reset(null, ref first, ref second);
            }

        public bool MoveToNext() {
            while (treeNodeIterator.MoveNext()) {
                TreeNodeItem item = treeNodeIterator.Current;
                SElement ancestor = item.Element;
                switch (item.Location) {
                    case TreeNodeLocation.None:
                        Debug.Assert(false, "The tree node iterator is moved to the 'None' item.");
                        throw new InvalidOperationException();
                    case TreeNodeLocation.Ancestor:
                        Debug.Assert(false, "The tree node iterator is moved to the 'Ancestor' item.");
                        throw new InvalidOperationException();
                    case TreeNodeLocation.Previous:
                        if (blockAllocator.CanAllocate(block, ancestor)) {
                            block.InsertAtEnd(ancestor);
                            current = ancestor;
                            return true;
                            }
                        break;
                    case TreeNodeLocation.Next:
                        if (blockAllocator.CanAllocate(block, ancestor)) {
                            block.InsertAtStart(ancestor);
                            current = ancestor;
                            return true;
                            }
                        break;
                    default:
                        throw new InvalidOperationException("Unknown the type of the tree node item.");
                    }
                }
            current = null;
            return false;
            }
        }
    }
